using System;
using System.Collections.Generic;
using System.Linq;
using EPiAbstractions.Community.Blog;
using EPiServer.Common.Cache;
using EPiServer.Common.Data;
using EPiServer.Common.Queries;
using EPiServer.Common.Sorting;
using EPiServer.Community.Blog;
using EPiServer.Community.Blog.Queries;

namespace JoelAbrahamsson.BlogExtensions
{
    public class ExtendedBlogHandlerFacade : BlogHandlerFacade
    {
        private const string GetLatestEntriesCacheKeyPrefix = "getLatestEntries";
        
        private delegate PagedCollectionResultSet GetLatestEntriesDelegate(Blog blog, int page, int pageSize);
        
        private GetLatestEntriesDelegate getLatestEntriesDelegate;

        public ExtendedBlogHandlerFacade()
        {
            getLatestEntriesDelegate = GetLatestEntriesUncached;
            EntryAdded += ExtendedBlogHandlerFacade_EntryAdded;
        }

        void ExtendedBlogHandlerFacade_EntryAdded(string sender, EPiServer.Common.EPiServerCommonEventArgs e)
        {
            Entry addedEntry = (Entry)e.Object;
            ClearGetLatestEntriesCache(addedEntry.Blog);
        }

        private void ClearGetLatestEntriesCache(Blog blog)
        {
            string[] cacheKey = new[] { GetLatestEntriesCacheKeyPrefix, blog.ID.ToString() };
            CacheHandler.RemoveCachedObject(cacheKey);
        }

        public virtual Entry GetEntryBySlug(string slug)
        {
            EntryQuery query = new EntryQuery();
            StringCriterion slugCriterion = new StringCriterion();
            slugCriterion.Value = slug;
            query[EntryExtensions.SLUG_ATTRIBUTE_NAME] = slugCriterion;
            EntryCollection matchingEntries = GetQueryResult(query);

            if (matchingEntries.Count == 0)
                return null;

            return matchingEntries[0];
        }

        public virtual EntryCollection GetLatestEntries(Blog blog, int page, int pageSize, out int totalItems)
        {
            string[] cacheKey = new [] { GetLatestEntriesCacheKeyPrefix, blog.ID.ToString(), page.ToString(), pageSize.ToString() };
            PagedCollectionResultSet latestEntries = (PagedCollectionResultSet) CacheHandler.GetCachedObject(
                getLatestEntriesDelegate, new object[] { blog, page, pageSize }, cacheKey);

            totalItems = latestEntries.TotalItems;

            return (EntryCollection) latestEntries.Collection;
        }

        public virtual PagedCollectionResultSet GetLatestEntriesUncached(Blog blog, int page, int pageSize)
        {
            EntryQuery query = new EntryQuery();
            query.Blog = new BlogCriterion();
            query.Blog.ID = new IntegerCriterion();
            query.Blog.ID.Value = blog.ID;
            query.PublicationStart = new DateTimeCriterion();
            query.PublicationStart.Value = DateTime.Now;
            query.PublicationStart.Operator = ComparisonOperator.LessThan;
            query.OrderBy.Add(new CriterionSortOrder(query.PublicationStart, SortingDirection.Descending));

            int totalItems;
            EntryCollection entries = QueryHandler.GetQueryResult<Entry, EntryCollection>(query, TimeSpan.Zero, page, pageSize, out totalItems);

            return new PagedCollectionResultSet(entries, totalItems);
        }

        public virtual IEnumerable<Entry> GetEntriesPublishedInMonth(int year, int month)
        {
            DateTime dateInMonth = new DateTime(year, month, 1);

            EntryQuery query = new EntryQuery();
            query.PublicationStart = new DateTimeCriterion();
            query.PublicationStart.DateResolution = DateResolution.Month;
            query.PublicationStart.Value = dateInMonth;
            query.OrderBy.Add(new CriterionSortOrder(query.PublicationStart, SortingDirection.Descending));
            
            EntryCollection entriesFromMonth = GetQueryResult(query);

            return entriesFromMonth.Where(entry => entry.PublicationStart <= DateTime.Now) ;
        }

        public virtual EntryCommentCollection GetLatestEntryComments(int page, int pageSize)
        {
            EntryCommentQuery query = new EntryCommentQuery();
            query.Created = new DateTimeCriterion();
            query.OrderBy.Add(new CriterionSortOrder(query.Created, SortingDirection.Descending));
            return QueryHandler.GetQueryResult<EntryComment, EntryCommentCollection>(query);
        }
    }
}
